connect API
上篇文章庖丁解牛React-Redux(一): connectAdvanced介绍了react-redux的Provider
、connectAdvanced
几个重要API的原理,其中connectAdvanced
是connect
函数的基础,这篇文章将主要介绍connect
函数的原理。之前没有阅读过connectAdvanced
最好提前阅读一下这篇文章。之前的文章有读者反映看起来比较晦涩,所以我准备随后会出一篇关于类似图解connectAdvanced
的文章,不讲代码,主要从原理的方面诠释connectAdvanced
。再次做个广告,欢迎大家关注我的掘金账号和我的博客。
最开始我们还是来介绍一下connect
函数:
connect([mapStateToProps], [mapDispatchToProps], [mergeProps], [options])
将React组件连接到Redux store,connect
函数是connectAdvanced
的正面,为大多数常见场景提供了易于使用的API。connect
函数并不会修改传递的组件,相反,它会返回一个新的,连接到store
的组件类。
参数:
[mapStateToProps(state, [ownProps]): stateProps](Function):
如果这个参数被传递,返回新的组件将会订阅Redux的store的更新(update)。这意味着任何时刻store
更新,mapStateToProps
将会被调用。mapStateToProps
必须返回一个纯对象(plain object),这个对象将会合并进组件的属性(props)。如果你不想订阅store的更新,可以给mapStateToProps
参数传递null
或者undefined
。
如果你的mapStateToProps
函数被声明接受两个参数,mapStateToProps
在调用时第一个参数是store state
,传递给连接组件(connected component)的属性将会被作为第二个参数。如果连接组件接受到新的props(浅比较),mapStateToProps
也会再次调用。
注意: 在一些更高级的情况下,你需要更好的控制渲染的性能,
mapStateToProps
可以返回一个函数。这种场景下,返回的函数将会被作为特定组件实例的mapStateProps()
函数。这允许你可以对每个实例缓存。但大部分应用用不到。
mapStateToProps
函数接受一个参数: Redux中store的state,并返回一个对象作为属性返回给被包裹的组件。这通常被称为`selector。
mapDispatchToProps(dispatch, [ownProps]): dispatchProps:
如果传入参数是一个对象,对象中的每个函数都被认为是Redux的action creator函数。返回的对象中的每个action creator函数都会被dispatch
所包裹,因此可以直接调用,最终会被合并进入组件的属性。
如果传递一个函数,该函数的第一个参数为dispatch
。需要你返回一个对象,其中的属性以你的方式将dispatch
与action creator相绑定。
如果你的mapDispatchToProps
函数声明接受两个参数,第一个函数是dispatch
,第二个参数是传递给连接组件的属性。每当连接组件收到新的参数时,mapDispatchToProps
就会被再次调用。
如果没有传入自定义的mapDispatchToProps
函数或者对象,默认的mapDispatchToProps
将为你的组件注入dispatch
属性。
注意:
mapDispatchToProps
也可以返回函数,用法与mapStateToProps
相同
mergeProps(stateProps, dispatchProps, ownProps): props:
如果指定了这个参数,传入的参数为:函数 mapStateToProps()
、mapDispatchToProps()
的运行结果以及传入连接组件的属性。从该函数返回的对象将会被当做属性传递给被包裹的组件。你可能会指定这个函数来基于props来选择性传入state,或者按照传入props绑定action creator。如果你省略了这个函数,默认是实现方式是:`
Object.assign({}, ownProps, stateProps, dispatchProps)
`
-
options
如果你指定了这个选项,更进一步自定义connector的行为。除了可以传入connectAdvanced
的选项,还可以接受额外的选项:[pure] (Boolean): 如果参数为true,用来避免重新渲染并调用
mapStateToProps
、mapDispatchToProps
和mergeProps
时基于各自的等值比较函数来比较所涉及到的state
和props
对象。[areStatesEqual] (Function): 如果参数
pure
为true
,用来比较传入的store与之前的store值。默认值: strictEqual (===)。[areOwnPropsEqual] (Function):如果参数
pure
为true
,用来比较传入的props与之前的props值。默认值: strictEqual (===)。[areStatePropsEqual] (Function):如果参数
pure
为true
,用以比较mapStateToProps
函数的结果与之前的结果值。[areMergedPropsEqual] (Function): 如果参数
pure
为true
,比较mergeProps
函数的结果与之前的值。默认值为:shallowEqual。[storeKey] (String): 用以从context获取store的key值。你仅仅可能在有多个store值的情况下才需要这个选项,默认值为:
store
。
connect源码
connect
的代码如下:
export function createConnect({
connectHOC = connectAdvanced,
mapStateToPropsFactories = defaultMapStateToPropsFactories,
mapDispatchToPropsFactories = defaultMapDispatchToPropsFactories,
mergePropsFactories = defaultMergePropsFactories,
selectorFactory = defaultSelectorFactory
} = {}) {
return function connect(
mapStateToProps,
mapDispatchToProps,
mergeProps,
{
pure = true,
areStatesEqual = strictEqual,
areOwnPropsEqual = shallowEqual,
areStatePropsEqual = shallowEqual,
areMergedPropsEqual = shallowEqual,
...extraOptions
} = {}
) {
const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, 'mapStateToProps')
const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, 'mapDispatchToProps')
const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')
return connectHOC(selectorFactory, {
methodName: 'connect',
getDisplayName: name => `Connect(${name})`,
shouldHandleStateChanges: Boolean(mapStateToProps),
initMapStateToProps,
initMapDispatchToProps,
initMergeProps,
pure,
areStatesEqual,
areOwnPropsEqual,
areStatePropsEqual,
areMergedPropsEqual,
...extraOptions
})
}
}
const connect = createConnect();
createConnect
作为高阶函数,返回connect
函数,通过柯里化的方式首先接受以下参数: connectHOC
、mapStateToPropsFactories
、mapDispatchToPropsFactories
、mergePropsFactories
与selectorFactory
。
connectHOC
传入用来生成连接到store的高阶组件(HOC),默认是之前介绍过的connectAdvanced
。
selectorFactory
selectorFactory
用来生成selector
,第一个参数将传入connectAdvanced
。我们知道传入connectAdvanced
的selectorFactory
函数主要是初始化selector函数。selector函数在每次connector component需要计算新的props都会被调用,selector函数会返回纯对象(plain object),这个对象会作为props传递给被包裹的组件(WrappedComponent)。selectorFactory
的函数签名为:
selectorFactory(dispatch, factoryOptions): selector(state, ownProps): props (Function)
我们来看看redux
的selectorFactory
是怎么定义的:
const selectorFactory = finalPropsSelectorFactory(dispatch, {
initMapStateToProps,
initMapDispatchToProps,
initMergeProps,
...options
}) {
const mapStateToProps = initMapStateToProps(dispatch, options)
const mapDispatchToProps = initMapDispatchToProps(dispatch, options)
const mergeProps = initMergeProps(dispatch, options)
if (process.env.NODE_ENV !== 'production') {
verifySubselectors(mapStateToProps, mapDispatchToProps, mergeProps, options.displayName)
}
const selectorFactory = options.pure
? pureFinalPropsSelectorFactory
: impureFinalPropsSelectorFactory
return selectorFactory(
mapStateToProps,
mapDispatchToProps,
mergeProps,
dispatch,
options
)
}
selectorFactory
函数首先接受两个参数,dispatch
和一系列的factoryOptions
,通过一系列的初始化函数分别生成了mapStateToProps
、mapDispatchToProps
、mergeProps
(初始化函数随后会详细介绍)。然后会在非生产环境下对上述三个函数进行验证(验证主要涉及到该函数是否为空和函数中是否有dependsOnOwnProps属性,这个属性随后会介绍的)。随后便是函数的重点部分,根据options.pure
是否为true,选择恰当的selectorFactory
,然后返回selectorFactory(...args)
。
当options.pure
为false
时,selectorFactory
的值为:impureFinalPropsSelectorFactory
:
function impureFinalPropsSelectorFactory(
mapStateToProps,
mapDispatchToProps,
mergeProps,
dispatch
) {
return function impureFinalPropsSelector(state, ownProps) {
return mergeProps(
mapStateToProps(state, ownProps),
mapDispatchToProps(dispatch, ownProps),
ownProps
)
}
}
我们知道,selectorFactory
会返回selector
函数,返回的函数会接受两个参数:state
与ownProps
并最终返回属性传递给被包裹的组件。我们发现impureFinalPropsSelectorFactory
非常的简单,只是单纯的将要求的参数传递给mapStateToProps
,mapDispatchToProps
,并将其结果连同ownProps
一起传递给mergeProps
,并将最后mergeProps
的结果作为selector
函数的结果。这个结果最终会传递给被包裹组件,这个函数没有什么难度而且非常符合connect
函数的API。
但我们知道在默认情况下,options.pure
为true
。因此selectorFactory
的值为:pureFinalPropsSelectorFactory
:
pureFinalPropsSelectorFactory(
mapStateToProps,
mapDispatchToProps,
mergeProps,
dispatch,
{ areStatesEqual, areOwnPropsEqual, areStatePropsEqual }
) {
let hasRunAtLeastOnce = false
let state
let ownProps
let stateProps
let dispatchProps
let mergedProps
// ......
return function pureFinalPropsSelector(nextState, nextOwnProps) {
return hasRunAtLeastOnce
? handleSubsequentCalls(nextState, nextOwnProps)
: handleFirstCall(nextState, nextOwnProps)
}
}
函数pureFinalPropsSelectorFactory
中有一个闭包变量hasRunAtLeastOnce
用来判断是否是第一次调用,如果selector
函数是第一次调用,selector
会返回handleFirstCall(nextState, nextOwnProps)
否则返回handleSubsequentCalls(nextState, nextOwnProps)
。
function handleFirstCall(firstState, firstOwnProps) {
state = firstState
ownProps = firstOwnProps
stateProps = mapStateToProps(state, ownProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
hasRunAtLeastOnce = true
return mergedProps
}
handleFirstCall
与之前的impureFinalPropsSelector
相比,只是做了缓存,保存了state
、ownProps
以及mapStateToProps
、dispatchProps
和mergedProps
的结果值。
function handleSubsequentCalls(nextState, nextOwnProps) {
const propsChanged = !areOwnPropsEqual(nextOwnProps, ownProps)
const stateChanged = !areStatesEqual(nextState, state)
state = nextState
ownProps = nextOwnProps
if (propsChanged && stateChanged) return handleNewPropsAndNewState()
if (propsChanged) return handleNewProps()
if (stateChanged) return handleNewState()
return mergedProps
}
再看函数handleSubsequentCalls
。其中areOwnPropsEqual
、areStatesEqual
分别用来判断props和state现在的值与缓存的值是否相等函数。handleSubsequentCalls
首先判断state、props的前后值是否有变化,然后缓存了state
、ownProps
。如果props和state都发送改变了,返回handleNewPropsAndNewState
的结果,如果props
改变了,返回handleNewProps
的运行结果。如果state
改变,返回handleNewState
运行结果,否则如果state
和props
都没发生改变,说明都没有发生改变。直接返回之前缓存的mergedProps
的值。
handleNewPropsAndNewState
定义如下:
function handleNewPropsAndNewState() {
stateProps = mapStateToProps(state, ownProps)
if (mapDispatchToProps.dependsOnOwnProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}
我们看到,如果props和state都发送改变了,调用了handleNewPropsAndNewState
,首先就是运行mapStateToProps
返回stateProps
的值并缓存,其次我们会根据mapDispatchToProps.dependsOnOwnProps
的值去判别是否运行mapDispatchToProps
。dependsOnOwnProps
的值主要是用来判别mapDispatchToProps
是否依赖于ownProps的值。最终执行mergeProps
函数,缓存结果并传入被包裹的组件。
function handleNewProps() {
if (mapStateToProps.dependsOnOwnProps)
stateProps = mapStateToProps(state, ownProps)
if (mapDispatchToProps.dependsOnOwnProps)
dispatchProps = mapDispatchToProps(dispatch, ownProps)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}
理解了handleNewPropsAndNewState
,handleNewProps
将会非常简单,分别去判别state
与dispatchProps
是否与ownProps相关。以判别是否需要重新运行mapStateToProps
和mapDispatchToProps
。最终将mergeProps
运行的值缓存并传递给被包裹的组件。
function handleNewState() {
const nextStateProps = mapStateToProps(state, ownProps)
const statePropsChanged = !areStatePropsEqual(nextStateProps, stateProps)
stateProps = nextStateProps
if (statePropsChanged)
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
return mergedProps
}
handleNewState
用来生成新的state。根据是否state
变化,选择性是否执行mergeProps
,最终返回mergedProps
给被包裹组件。
到现在为止,其实我们已经知道了selectorFactory
是与pure
值挂钩的。如果pure
为true
的话,selectorFactory
返回的selector
会对state
和props
等值都会缓存,然后会根据具体的场景,尽可能使得传入被包裹组件的值改动最少(即尽可能返回相同的值),其目的就是减少不必要的渲染。当pure
为false
值,不会做任何的缓存。
mapStateToProps起源
看完了selectorFactory
,我们需要去了解一下mapStateToProps
是怎么来的:
//connect.js
// initMapStateToProps会被传入 selectorFactory
const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, 'mapStateToProps')
//selectorFactory.js
const mapStateToProps = initMapStateToProps(dispatch, options)
//mapStateToProps的使用(注意这里的mapStateToProps不是传入的函数,而是init函数生成的函数):
const stateProps = mapStateToProps(state, ownProps)
我们可以看到,首先在connect.js
中通过match
函数取生成initMapStateToProps
。然后在selectorFactory
中,生成了mapStateToProps
的函数,然后会在selector
函数中使用mapStateToProps
生成了stateProps
,最后将stateProps
传递给被包裹的组件。
首先看match
函数的定义:
function match(arg, factories, name) {
for (let i = factories.length - 1; i >= 0; i--) {
const result = factories[i](arg)
if (result) return result
}
return (dispatch, options) => {
throw new Error(`Invalid value of type ${typeof arg} for ${name} argument when connecting component ${options.wrappedComponentName}.`)
}
}
接下来的内容相对来说会比较复杂,我们先提前梳理一下match
函数的运作,其中factories
是一个数组,它的实参将会是类似于mapStateToPropsFactories
(数组)等值,然后args
将是你自定义的mapStateToProps
函数等值(比如mapStateToDispatch
)。我们将会以args
作为参数从后到前执行factories
数组中的每一个函数,找到第一个返回不为假(类似于undefined
)的函数并且我们可以保证这个函数返回的是另一个函数,其签名类似于:
(dispatch,options)=>{
//....
return ()=>{
}
}
这个返回的函数接受dispatch
和其他选项options
作为参数,最终返回一个函数供selector
使用的函数 ,比如mapStateToPropsFactories
一定会返回一个类似与于下面的函数:
(state, ownProps) =>{
//......
//return plain object
}
这个函数将用来计算新的state传递给被包裹的组件。
对于mapStateToProps
的来源要追溯到:
const initMapStateToProps = match(mapStateToProps, mapStateToPropsFactories, 'mapStateToProps')
在函数match
中第一个实参是你传入connect
的mapStateToProps
。第二个实参mapStateToPropsFactories
的定义如下:
const mapStateToPropsFactories = [
whenMapStateToPropsIsFunction,
whenMapStateToPropsIsMissing
];
function whenMapStateToPropsIsFunction(mapStateToProps) {
return (typeof mapStateToProps === 'function')
? wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps')
: undefined
}
function whenMapStateToPropsIsMissing(mapStateToProps) {
return (!mapStateToProps)
? wrapMapToPropsConstant(() => ({}))
: undefined
}
上面的代码都不难,首先判断传入的mapStateToProps
是不是类似于null
,如果是执行whenMapStateToPropsIsMissing
否则去执行whenMapStateToPropsIsFunction
。对于whenMapStateToPropsIsMissing
来说,重要的是whenMapStateToPropsIsMissing
的定义:
function wrapMapToPropsConstant(getConstant) {
return function initConstantSelector(dispatch, options) {
const constant = getConstant(dispatch, options)
function constantSelector() { return constant }
constantSelector.dependsOnOwnProps = false
return constantSelector
}
}
wrapMapToPropsConstant
函数接受的参数是一个函数,这个函数负责在selector
返回一个常量作为props返回给被包裹组件。因为返回的总是一个常量,所以dependsOnOwnProps
为false
,表示返回给被包裹组件的值与连接到store的高阶组件接受到的props
无关。
那么whenMapStateToPropsIsMissing
函数调用wrapMapToPropsConstant
的参数是一个空函数(()=>{}
),那就说明在mapStateToProps
值为空(null
)的时候,是不给被包裹组件传递任何的属性的。
whenMapStateToPropsIsFunction
的情况会比较复杂,如果传入的mapStateToProps
是一个函数,那么就会调用wrapMapToPropsFunc
:
function wrapMapToPropsFunc(mapToProps, methodName) {
return function initProxySelector(dispatch, { displayName }) {
const proxy = function mapToPropsProxy(stateOrDispatch, ownProps) {
return proxy.dependsOnOwnProps
? proxy.mapToProps(stateOrDispatch, ownProps)
: proxy.mapToProps(stateOrDispatch)
}
proxy.dependsOnOwnProps = true
proxy.mapToProps = function detectFactoryAndVerify(stateOrDispatch, ownProps) {
proxy.mapToProps = mapToProps
proxy.dependsOnOwnProps = getDependsOnOwnProps(mapToProps)
let props = proxy(stateOrDispatch, ownProps)
if (typeof props === 'function') {
proxy.mapToProps = props
proxy.dependsOnOwnProps = getDependsOnOwnProps(props)
props = proxy(stateOrDispatch, ownProps)
}
if (process.env.NODE_ENV !== 'production')
verifyPlainObject(props, displayName, methodName)
return props
}
return proxy
}
}
wrapMapToPropsFunc
的函数相对来说比较复杂,接受的参数是你传入的mapStateToProps
函数(methodName
的作用只是错误提示),返回的是初始化selector
函数(initProxySelector
)。当使用initProxySelector
初始化selector
的时候,返回的函数proxy
实则为一个代理(proxy
)。第一次执行proxy
(selector
)时,dependsOnOwnProps
的值为true
,所以相当于执行proxy.mapToProps(stateOrDispatch, ownProps)
(detectFactoryAndVerify
),然后将proxy.mapToProps
属性设置为你所传入的mapStateToProps
函数。这时候再去执行getDependsOnOwnProps
的目的是去确定你传入的mapStateToProps
是否需要传入props
。然后再去执行proxy(stateOrDispatch, ownProps)
,这时候proxy.mapToProps
已经不是之前的detectFactoryAndVerify
而是你传入的mapStateToProps
(所以不会出现死循环)。执行的结果就是mapStateToProps
运行后的结果。如果prop
是对象,将会直接传递给被包裹组件。但是我们之前讲过,mapStateToProps
是可以返回一个函数的,如果返回的值为一个函数,这个函数将会被作为proxy
的mapStateToProps
,再次去执行proxy
。
mapDispatchToProps起源
再去了解一下mapStateToProps
的来源:
//connect.js
const initMapDispatchToProps = match(mapDispatchToProps, mapDispatchToPropsFactories, 'mapDispatchToProps')
//selectFactory
const mapDispatchToProps = initMapDispatchToProps(dispatch, options)
//使用:
const dispatchProps = mapDispatchToProps(dispatch, ownProps)
其实mapDispatchToProps
是和mapStateToProps
的来源非常相似,照理看mapDispatchToPropsFactories
:
const mapDispatchToPropsFactories = [
whenMapDispatchToPropsIsFunction,
whenMapDispatchToPropsIsMissing,
whenMapDispatchToPropsIsObject
]
function whenMapDispatchToPropsIsFunction(mapDispatchToProps) {
return (typeof mapDispatchToProps === 'function')
? wrapMapToPropsFunc(mapDispatchToProps, 'mapDispatchToProps')
: undefined
}
function whenMapDispatchToPropsIsMissing(mapDispatchToProps) {
return (!mapDispatchToProps)
? wrapMapToPropsConstant(dispatch => ({ dispatch }))
: undefined
}
function whenMapDispatchToPropsIsObject(mapDispatchToProps) {
return (mapDispatchToProps && typeof mapDispatchToProps === 'object')
? wrapMapToPropsConstant(dispatch => bindActionCreators(mapDispatchToProps, dispatch))
: undefined
}
如果你已经看懂了wrapMapToPropsConstant
和wrapMapToPropsFunc
的函数的话,mapDispatchToPropsFactories
也就不难了。如果传入的mapStateToProps
的值是一个对象的话,会调用whenMapDispatchToPropsIsObject
。继而调用了wrapMapToPropsConstant
并传入的参数是函数:dispatch => bindActionCreators(mapDispatchToProps, dispatch)
。根据我们之前经验,那么传递给被包裹的组件的属性将是:bindActionCreators(mapDispatchToProps, dispatch)
的运行结果,即被dispatch
包裹的action
。
如果没有传入mapDispatchToProps
函数的话,调用whenMapDispatchToPropsIsMissing
。传入函数wrapMapToPropsConstant
的参数为:dispatch => ({ dispatch })
,那么被包裹的组件接受的参数即是store
的dispatch
方法。
如果传入的mapDispatchToProps
是一个函数,调用whenMapDispatchToPropsIsFunction
函数。从而调用wrapMapToPropsFunc(mapDispatchToProps, 'mapDispatchToProps')
。运行的原理与运行wrapMapToPropsFunc(mapStateToProps, 'mapStateToProps')
基本相同,可以参照之前。
mergeProps起源
//connect.js
const initMergeProps = match(mergeProps, mergePropsFactories, 'mergeProps')
//selectorFactory
const mergeProps = initMergeProps(dispatch, options)
//使用
mergedProps = mergeProps(stateProps, dispatchProps, ownProps)
还是先看一下mergePropsFactories
是怎么定义的:
const mergePropsFactories = [
whenMergePropsIsFunction,
whenMergePropsIsOmitted
]
function whenMergePropsIsFunction(mergeProps) {
return (typeof mergeProps === 'function')
? wrapMergePropsFunc(mergeProps)
: undefined
}
function whenMergePropsIsOmitted(mergeProps) {
return (!mergeProps)
? () => defaultMergeProps
: undefined
}
如果你没有传入mapStateToProps
函数,那么调用函数whenMergePropsIsOmitted()
。到最后margedProps
函数即是defaultMergeProps
,defaultMergeProps
的定义为:
function defaultMergeProps(stateProps, dispatchProps, ownProps) {
return { ...ownProps, ...stateProps, ...dispatchProps }
}
如果你传入了mapStateToProps
函数,调用函数whenMergePropsIsFunction()
,调用了wrapMergePropsFunc(mergeProps)
,其中参数mergeProps
即是你所传入的mergeProps
:
function wrapMergePropsFunc(mergeProps) {
return function initMergePropsProxy(dispatch, { displayName, pure, areMergedPropsEqual }) {
let hasRunOnce = false
let mergedProps
return function mergePropsProxy(stateProps, dispatchProps, ownProps) {
const nextMergedProps = mergeProps(stateProps, dispatchProps, ownProps)
if (hasRunOnce) {
if (!pure || !areMergedPropsEqual(nextMergedProps, mergedProps))
mergedProps = nextMergedProps
} else {
hasRunOnce = true
mergedProps = nextMergedProps
if (process.env.NODE_ENV !== 'production')
verifyPlainObject(mergedProps, displayName, 'mergeProps')
}
return mergedProps
}
}
}
wrapMergePropsFunc
中涉及到性能优化,首先wrapMergePropsFunc
返回一个初始mergeProps
的函数(mergePropsProxy
)。函数mergePropsProxy
闭包一个变量hasRunOnce
来记录mergeProps
运行次数,在mergeProps
第一次运行时,会保存第一次传入被包裹组件的的props
,再以后的运行过程中,如果你传入的参数pure
为true
并且前后的mergedProps
值不同时(比较函数你可以自定义)才会传入新的属性,否则将传入之前的缓存值,以此来优化不必要的渲染。
到此为止,我们基本已经在代码层面讲完了connect
函数的原理,文章很长,有的地方可能相对比较难理解,建议大家都可以去从整体上看看react-redux
的源码。react-redux
源码解读系列接下来会以其他的角度去分析react-redux
,欢迎大家继续关注。
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。